Repository navigation
fix(studio): undo paints a move or nudge back at once while its save is still running - #4877
Merged
Merged
Conversation
miguel-heygen
force-pushed
the
studio/undo-waits-for-committed-edit
branch
from
October 1, 2026 18:50
b16fca2 to
a3e9889
Compare
miguel-heygen
force-pushed
the
studio/undo-paints-pending-edit-revert
branch
from
October 1, 2026 18:52
3c782fb to
4235a4e
Compare
miguel-heygen
force-pushed
the
studio/undo-waits-for-committed-edit
branch
from
October 1, 2026 19:23
a3e9889 to
bedf393
Compare
miguel-heygen
force-pushed
the
studio/undo-paints-pending-edit-revert
branch
from
October 1, 2026 19:56
4235a4e to
a966766
Compare
miguel-heygen
force-pushed
the
studio/undo-waits-for-committed-edit
branch
from
October 1, 2026 21:22
c527274 to
0532755
Compare
miguel-heygen
force-pushed
the
studio/undo-paints-pending-edit-revert
branch
from
October 1, 2026 22:37
a966766 to
017b325
Compare
Edit accuracy: 953 passing here, 953 on the base branchThe gate passes. Quarantined, measured but not gated (0) Unstable (2)
|
miguel-heygen
force-pushed
the
studio/undo-paints-pending-edit-revert
branch
2 times, most recently
from
October 2, 2026 02:04
98e2226 to
63e3aa2
Compare
miguel-heygen
marked this pull request as ready for review
October 2, 2026 02:50
miguel-heygen
force-pushed
the
studio/undo-paints-pending-edit-revert
branch
from
October 2, 2026 02:58
63e3aa2 to
fcbb0b0
Compare
…sees it The nudge step already waits a frame per key (sequences.mjs:162); undo and the text step's Enter now do too.
miguel-heygen
force-pushed
the
studio/undo-paints-pending-edit-revert
branch
from
October 2, 2026 03:28
fcbb0b0 to
2368918
Compare
This was referenced Oct 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
If you press Cmd+Z while a move or a nudge is still saving, the box now jumps back to where it was in the same frame as the key. Before, it stayed at the moved place until the save and the server's undo had both landed. Under load that was often a second or more, so a drag started from what was on screen then jumped.
Why
Undo's instant paint (from #4798) predicts the step from this tab's history and shows it in place. An edit that is still saving has no history entry yet, so the prediction would show the edit before it, and the paint is refused. The screen then waited for the server.
The same gap stayed open briefly after each save: the save ended before the history list holding its entry had been fetched, so for that moment the edit was neither pending nor known to the history.
How
recordEditnow waits for the history list it fetches after a claim. A save therefore ends only once undo can predict it, which closes the gap above. The fetch was already requested after every claim (void refresh()); it is now awaited, so there is no extra request, and a save ends when that fetch returns instead of before it.seqrepeat-none-px-r0-nested-z100andsequndo-none-px-r0-root-z100are out of the quarantine list. The quarantine list is now empty.Why the bench needed the frame
The drag that follows an undo read the box with CDP
DOM.getContentQuads0 to 4 ms after Studio had already moved it back in the DOM. In the failing runs that read still returned the spot before the undo, whilegetBoundingClientRecton the same element right after returned the spot after it. Reads that passed had a frame between the undo and the read.recordEditwait (gsap=none, 6 cases a run)recordEditwaitSo the bench pressed where the box had been before the frame that showed the undo. Two frames later, at mouse down, the box was no longer there, and the press started no drag. Before this PR the box stayed put until the server's undo, which hid the race.
Bench
On one machine, 3 jobs, three runs of each build, with this branch's bench:
Both builds pass every run once the bench waits for the frame, so this table shows no regression; it does not measure the gain. The gain is how soon the box shows undone, which is in the captures below. "This PR" is the build one commit before the head; the only later change removes a code comment. In CI the gate passes, with nothing newly passing or unbanked: main's baseline already banks both ids taken off the quarantine list as passing.
Test plan
studioPendingEdits.test.ts: only the newest edit is painted back, once, and shown again on request; nothing is painted when the newest edit has no revert; what an edit starts inside its registration is part of it; an edit whose start throws ends its registration. The last fails when a throwing start does not end the registration.dragUndoPaint.test.ts: a drag whose save is still running can be painted back at once and shown again, and stops counting once its save lands. Fails when the drag registers no revert.useEditHistoryActions.paint.test.tsx, over the real history engine:Both fail without the revert paint; the second also fails when the burst's commit redraws it.
usePersistentEditHistory.test.ts: with the history list slowed by 50 ms, the step is predicted as soon as the save ends. Fails whenrecordEditdoes not wait for the list.Bench unit tests (
tests/e2e/edit-accuracy), the Studio suite, typecheck, oxlint, oxfmt.Before
A move in a bench fixture with every save slowed to 1.5 s, Ctrl+Z on the frame after release, on #4807: the box stays at the moved place until the server's undo lands.
After
The same on this branch: the box is back in the first frame after the key and stays there.
How to read the panels: each one is the last frame the browser's screencast sent at or before that time. The screencast sent no frame between 107 ms before the key and 107 ms after it, so the "50 ms after" panel repeats the frame from before the key. The first frame after the key, at 107 ms, already shows the box back at its start; the selection outline has caught up by the next frame it sent, at 209 ms. The strip cannot show how soon the box paints. That comes from the tests, which check that the box is back in the key's own task. The capture was taken on a build of the first commit of this branch; later commits change neither the move nor its revert.